/* 
 * File:   QueryModifier.hpp
 * Author: Faisal
 *
 * Created on April 27, 2012, 8:39 PM
 *
 * Description:
 *
 *		This class will be used to handle the parameters, filters, order clause and any other modifications to the query. It's a templated class that will keep the
 *		business object reference. All it's method to add query modifiers will return this class again to support the Fluent pattern and user can keep adding the elements.
 *		e.g. QueryModifer.addParameter(param1).addparameter(param2).addFilter(fitler1).addFilter(filter2).addOrder(order1).
 */

#ifndef HQueryModifier_Core

#define HQueryModifier_Core

#include "Shared.hpp"
#include "Common/Include/FilterType.hpp"
#include "boost/any.hpp"
#include "Common/Include/QueryModifierBase.hpp"
#include "Common/Include/BusinessBase.hpp"

using Supetronix::PersistO::Common::FilterType;
using Supetronix::PersistO::Common::BusinessBase;
using Supetronix::PersistO::Common::ParameterInfo;
using Supetronix::PersistO::Common::QueryModifierBase;

using std::string;
using std::vector;
using std::shared_ptr;
using std::unique_ptr;

namespace Supetronix
{
	namespace PersistO
	{
		namespace Core
		{
			//bo class is the "BusinessObject" type
			// TODO:  
			//		need to implement the logic in "getParameterList" to order the internal parameter collection.
			//		1. first order all the parameters
			//		2. second order all the filter conditions
			//		we need to do it so it will be easier to build the query and use the indexed position of parameters
			template<class bo>
			class QueryModifier : QueryModifierBase
			{
			public:
				/*
				*	Methods
				*/
				virtual QueryModifier<bo>* addFilter(FilterType filterType, const string& columnName, boost::any data) override final;
				virtual QueryModifier<bo>* addParameter(const std::string& parameterName, boost::any data) override final;
				virtual unique_ptr<bo> execute(void);// override final;
				virtual shared_ptr<vector<ParameterInfo>> getParameterList() const override final;

				/*
				*	contructor and destructor
				*/
				//constructor requires the business object reference and the query text
				QueryModifier(bo* targetBO, const string& query) : _targetBO(targetBO), _query(query)
				{
					_parameters.reset(new vector<ParameterInfo>());
				}

				~QueryModifier()
				{					
					//delete the parameters vector
					_parameters->clear();
					_parameters.reset();
				}

			private:
				/*
				*	Member variables
				*/

				//list of parameters for the query
				shared_ptr<vector<ParameterInfo>> _parameters;

				//the business object that will be returned by the query
				bo* _targetBO;

				//query text
				string _query;
			};

			/*
			*
			*	Implementation need to be moved to a separate file
			*
			*/

			//add the specific filter to the internal parameter collection
			template<class bo>
			QueryModifier<bo>* QueryModifier<bo>::addFilter(FilterType filterType, const std::string& columnName, boost::any data)
			{
				_parameters->push_back(ParameterInfo(columnName, filterType, data));
				return this;
			}

			//add the parameters like stored procs parameters etc to internal parameter list
			template<class bo>
			QueryModifier<bo>* QueryModifier<bo>::addParameter(const std::string& parameterName, boost::any data)
			{
				_parameters->push_back(ParameterInfo(parameterName, data));
				return this;
			}

			//once all the filters are created then call the execute which will internally call the business object execute to get the data
			template<class bo>
			unique_ptr<bo> QueryModifier<bo>::execute(void)
			{
				return unique_ptr<bo>(_targetBO->execute(QueryType::Select, "", this));
			}

			//it will return the list of all parameters created in the query modifier
			template<class bo>
			shared_ptr<vector<ParameterInfo>> QueryModifier<bo>::getParameterList() const
			{
				return _parameters;
			}
		}
	}
}

#endif